package com.example.demo.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 * 类描述信息
 *
 * @author TongDaShuai
 * @since 2021/9/2
 */
@Controller
@Slf4j
public class ImageController {
    private static final Random RANDOM = new Random();

    @RequestMapping("genValidateCode")
    public void genValidateCode (HttpServletRequest request, HttpServletResponse response) throws Exception {
        getRandcode(request, response);
    }

    @PostMapping(value = "/imageup/{type}")
    @ResponseBody
    public String fileUpload(@RequestParam(value = "file") MultipartFile file, HttpServletRequest request) {
        if (file.isEmpty()) {
            System.out.println("文件为空空");
        }
        String fileName = file.getOriginalFilename();  // 文件名
//        String suffixName = fileName.substring(fileName.lastIndexOf("."));  // 后缀名
        String filePath = "C://Users//Administrator//Desktop//temp//image//"; // 上传后的路径
        fileName = UUID.randomUUID() + "_" + fileName; // 新文件名
        File dest = new File(filePath + fileName);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try {
            file.transferTo(dest);
        } catch (IOException e) {
            e.printStackTrace();
        }

        String json = "{\n" +
                "  \"data\": {\n" +
//                "    \"id\": 0\n" +
                "  },\n" +
                "  \"errorcode\": 1,\n" +
                "  \"message\": \"\"\n" +
                "}";
        return json;
    }


    /**
     * 生成文字选择图片验证码
     *  @param request
     * @param response
     */
    public static void getRandcode(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 校验key，用于和校验验证码的接口对应（可以app端生成一个唯一的key，也可以直接把学员报名id作为key）
        String key = request.getParameter("key");
        if (StrUtil.isBlank(key)) {
            log.error("用于校验验证码的key参数不存在");
            return;
        }

        // 默认宽高，不变动
        int width = 310, height = 130, lineSize = 40;

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);

        // 查字典（生成验证码的数据来源）
        List<String> list = new ArrayList<>();
        list.add("恭喜发财");

        // 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);
        // 绘制干扰线
//        drawLine(g, width, height, lineSize);
        // 绘制随机字符
        JSONObject randomString =  drawString(g, list);
        // 设置题目
        drawTitle(g, list.get(0), request);
        // 添加噪点
//        drawYawpRate(image);

        log.debug("验证码：" + randomString);


        g.dispose();
        try {
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            log.error("错误信息：", e);
        }
    }

    /*
     * 绘制干扰线
     */
    private static void drawLine(Graphics g, int width2, int height2, int lineSize) {
        Random random = new Random();
        for (int i = 0; i <= lineSize; i++) {
            g.setColor(getRandColor(1, 133));
            int x = RANDOM.nextInt(width2);
            int y = RANDOM.nextInt(height2 - 30) + 30;
            int xl = RANDOM.nextInt(width2);
            int yl = RANDOM.nextInt(height2 - 30) + 30;
            g.drawLine(x, y, xl, yl);
        }
    }

    /*
     * 获得颜色
     */
    private static Color getRandColor(int fc, int bc) {
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + RANDOM.nextInt(bc - fc);
        int g = fc + RANDOM.nextInt(bc - fc);
        int b = fc + RANDOM.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    private static void drawTitle(Graphics g, String string, HttpServletRequest request) {
        g.setFont(getFont());
        g.setColor(getRandColor(1,133));
        g.drawString("按顺序点击文字：" , 6, 26);

//        g.drawOval(6, 26, 20, 20);

        g.setColor(new Color(254, 0, 0));
        g.setFont(new Font("Fixedsys", Font.CENTER_BASELINE, 23));
        g.drawString(string , 149, 26);
//        g.drawLine(149, 26, 149+23, 26+23);
//        g.drawString(string , 149, 26 +23);
        //扭曲题目
        shear(g,310, 27, new Color(255,255,255), request);

    }


    /*
     * 获得字体
     */
    private static Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, 17);
    }

    // 扭曲方法
    private static void shear(Graphics g, int w1, int h1, Color color, HttpServletRequest request) {
        Integer level = 1;//验证难度
        shearX(g, w1, h1, color, level);
        shearY(g, w1, h1, color, level);

    }

    private static void shearX(Graphics g, int w1, int h1, Color color, Integer level) {
        int fontSize = 23;
        Random random = new Random();
        double max = 10/level, min = 5/level;//初始值
        Double period = random.nextDouble() * fontSize *(max-min) / Math.PI + fontSize*min/Math.PI; // 17px为一个字，一个π放min到max个字 字越多模糊效果越差
        int peak = (random.nextInt(1)+2) * level;//波峰最高取值范围1到4

        boolean borderGap = true;
        int frames = random.nextInt(25)+1;
        int phase = random.nextInt(25)+1;

        for (int i = 0; i < h1; i++) {
            double d = (double) peak * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
            g.copyArea(146, i, 310-146, 1, (int) d, 0);
            if (borderGap) {
                g.setColor(color);
                if(d>0) {
                    g.drawLine((int) d + 146, i, 146, i);
                }
                g.drawLine((int) d + w1, i, w1, i);
            }
        }

    }

    private static void shearY(Graphics g, int w1, int h1, Color color, Integer level) {
        int fontSize = 23;//字体大小
        Random random = new Random();
        double max = 15/level, min = 5/level;//单波峰最多包含文字和最少包含文字
        Double period = random.nextDouble() * fontSize *(max-min) / Math.PI + fontSize*min/Math.PI;//包含文字随机取最多和最少之间的double值
        int peak = (random.nextInt(2)+2) * level;//波峰上下限，等级越高越难识别，最后会超过图片限制
        boolean borderGap = true;//是否填充颜色
        int frames = random.nextInt(25)+1;//波浪线从哪里开始，随机
        int phase = random.nextInt(25)+1;//波浪线从哪里开始，随机
        for (int i = 149; i < w1; i++) {
            double d = (double) peak * Math.sin((double) i / period + (6.2831853071795862D * (double) phase) / (double) frames);
            g.copyArea(i, 0, 1, h1, 0, (int) d);
            if (borderGap) {
                g.setColor(color);
                g.drawLine(i, (int) d, i, 0);
                if(d<0) {
                    g.drawLine(i, (int) d + h1, i, h1);
                }
            }

        }

    }

    private static void drawYawpRate(BufferedImage image) {
        // 添加噪点
        Random random = new Random();
        float yawpRate = 0.01f;// 噪声率
        int area = (int) (yawpRate * 310 * 130);
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(310);
            int y = random.nextInt(130);

            image.setRGB(x, y, random.nextInt(255));
        }
    }


    private static JSONObject drawString(Graphics g, List<String> list) {
        JSONObject json = new JSONObject();
        StringBuffer sbuf = new StringBuffer();
        StringBuffer seedList = new StringBuffer();
//		List<Character> seedList = new ArrayList<Character>();
        for (String string : list) {
            seedList.append(string);
        }
        String seed = seedList.substring(0, 4);
        List key = new ArrayList();
        for (char c : seed.toCharArray()) {
            key.add(c);
        }
        Collections.shuffle(key);
        json.put("key", list.get(0));
        g.setFont(new Font("Fixedsys", Font.CENTER_BASELINE, 60));
        for(int y=0; y<1; y++) {
            for(int x=0; x<4; x++) {
                int rx = 0, ry = RANDOM.nextInt(25);
                String c = key.get(4*y+x)+"";
                g.setColor(getRandColor(1,133));
                g.drawString(c, 70*x+rx, 100+ry);
                sbuf.append(c).append("_").append(70*x+rx).append("_").append(100+ry).append(",");
            }
        }
        json.put("code", sbuf.toString());
        return json;
    }
}
